#include <linux/init.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/of.h>
#include <linux/of_gpio.h>

#include <asm/io.h>

#define KEY_NUMS 3

struct key_desc{
	char *name;
	int irqnum;
	int key_code;
	int gpionum;
	void *regbase;
	struct device_node *cnp;
};

struct key_desc all_key[KEY_NUMS];

struct input_dev *inputdev;


void get_all_child_from_node(void)
{
	struct device_node *cnp;
	struct device_node *prev=NULL;
	int i=0;

	//名字为节点
	struct device_node *np = of_find_node_by_path("/key_init_node");
	if(np)
	{
		printk("find node ok\n");
	}
	else
	{
		printk("find node failed\n");
	}
	
	do{
		cnp=of_get_next_child(np,prev);
		if(cnp!=NULL)
		{
			all_key[i++].cnp=cnp;
		}
		prev = cnp;
	}while(of_get_next_child(np,prev)!=NULL);
}

irqreturn_t input_key_irq_handler(int irqnum,void *devid)
{
	int value;
	int gpionum;
	struct key_desc *pdesc=(struct key_desc *)devid;
	gpionum=of_get_named_gpio(pdesc->cnp,"gpio",0);
	value = gpio_get_value(gpionum);
	if(value)
	{
		input_report_key(inputdev,pdesc->key_code,0);
		input_sync(inputdev);
	}
	else
	{
		input_report_key(inputdev,pdesc->key_code,1);
		input_sync(inputdev);
	}
	return IRQ_HANDLED;
}


static int __init input_init(void)
{
	int ret;
	int irqflags;
	int i;
	int code=0;
	int irqn;
	char *key_name=NULL;
	struct device_node *cnp;
	inputdev=input_allocate_device();
	if(inputdev==NULL)
	{
		printk(KERN_ERR "input_allocate_device failed\n");
		return -ENOMEM;
	}
	
	get_all_child_from_node();

	inputdev->name="input key";
	inputdev->phys="key/input/input0";
	inputdev->uniq="4412 key0";
	inputdev->id.bustype=BUS_HOST;
	inputdev->id.vendor=0x666;
	inputdev->id.product=0x777;
	inputdev->id.version=0x001;


	__set_bit(EV_KEY,inputdev->evbit);

	for(i=0;i<KEY_NUMS;i++)
	{
		cnp=all_key[i].cnp;

		of_property_read_u32(cnp,"key_code",&code);
		__set_bit(code,inputdev->keybit);
		all_key[i].key_code=code;


		irqn=irq_of_parse_and_map(cnp,0);
		all_key[i].irqnum=irqn;

		of_property_read_string(cnp,"key_name",&key_name);
		all_key[i].name=key_name;

		printk("name=%s,code=%d,irqnum=%d\n",key_name,code,irqn);

		irqflags=IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING;

		ret=request_irq(irqn,input_key_irq_handler,irqflags,key_name,&all_key[i]);
		if(ret!=0)
		{
			printk("request_irq failed\n");
			goto err_0;
		}
	}
	
	ret = input_register_device(inputdev);
	if(ret!=0)
	{
		printk("input_register_device failed\n");
		goto err_1;
	}
	return 0;


err_1:
input_unregister_device(inputdev);
err_0:
	input_free_device(inputdev);
	return ret;
}

static void __exit input_exit(void)
{
	int i;
	for(i=0;i<KEY_NUMS;i++)
	{
		free_irq(all_key[i].irqnum,&all_key[i]);
	}
	input_unregister_device(inputdev);
	input_free_device(inputdev);
}




module_init(input_init);
module_exit(input_exit);
MODULE_LICENSE("GPL");

